#include "jeremy.h"

int main(int argc, char *argv[])
{
	struct settings * nastaveni;
	struct main_structure * jeremy;
	struct settings * item;
	struct settings * headers;
	pid_t pid;

	printf("Jeremy - %s\nCopyright (c) Martin Kumst 2004, 2009\n\n", JEREMY_VERSION);

	/* Nabindovani akci k signalum */
	signal(SIGCHLD, kill_zombie);
	signal(SIGINT, termination);
	signal(SIGALRM, termination);

	/* Overime pocet argumentu, pokud je spatny tak koncime */
	if (argc != 2) death(ERR_ARGS, __func__);

	/* Nacteni nastaveni */
	nastaveni = (struct settings *) malloc(sizeof(struct settings));
	nastaveni->next_settings = NULL;
	if (nastaveni == NULL) death(ERR_MEM, __func__);
	if (!conf_file_parser(nastaveni, argv[1])) death(ERR_CONF_FILE, __func__);

	/* Inicializace stromu s hlavickami */
	headers = (struct settings *) malloc(sizeof(struct settings));
	headers->next_settings = NULL;

	/* Plneni hlavni struktury pro operace se siti */
	jeremy = (struct main_structure *) malloc(sizeof(struct main_structure));
	if (jeremy == NULL) death(ERR_MEM, __func__);

	item = get_settings(nastaveni, HTTP_PORT);
	if (item == NULL) death(ERR_CONF_FILE2, __func__);
	jeremy->http_port = atoi(item->value);

	/* Nastartovani serveru */
	start_server(jeremy);

	/* Nyni budeme cekat, na pripojeni klientu */
	for(;;) {
		wait_for_client(jeremy);
		pid = make_child(jeremy); 

		if (pid == 0) { /* Child obslouzi pripojeneho klienta a milostive zkonci */

			/* Nacteni http hlavicek */
			if (set_http_read_headers_timeout(jeremy, nastaveni) == false) death(ERR_ALARM, __func__);
			if (http_read_headers(jeremy, headers, nastaveni) == false) death(ERR_HTTP_HEADERS, __func__);
			if (DEBUG == true) printf("Bylo nacteno %d http hlavicek\n", num_settings(headers));
			if (http_check_min_headers(jeremy, headers) == false) {
				if (DEBUG == true) {
					printf("Nelze provest http pozadavek. Nebyly nacteny vsechny potrebne hlavicky od klienta.\n");
				}

				exit(0);
			}
			if (http_requested_filename(jeremy, headers) == false) death(ERR_HTTP_FILENAME, __func__);
			else {
				if (DEBUG == true) {
					printf("Klient pozaduje soubor: #%s#\n", jeremy->requested_filename);
				}
			}

			exit(0);
		}
		else { /* Parent bude cekat na dalsiho pripojeneho klienta */
			continue;
		}
	}

	return 0;
}

/* Nasilne ukonceni programu */
void death(char * msg, const char * function)
{
	printf("%s %s\n%s %s\n", DEATH_NOTE1, function, DEATH_NOTE2, msg);
	exit(0);
}

/* Vytvoreni detskeho procesu, ktery se bude dale starat o klienta, rodic zavre klientsky deskriptor a 
 * bude cekat na dalsiho klienta
 * Navratova hodnota je pid nove vytvoreneho procesu pro child, jinak v parentu vraci nulu */
pid_t make_child(struct main_structure * jeremy)
{
	pid_t pid;

	pid = fork();
	if (pid != 0) { /* V parentu zavreme klientsky socket */
		close(jeremy->client_fd);
	}

	return pid;
}

/* Zabijeme vsechny zombie procesy, ktere na nas visi */
void kill_zombie(int n)
{
	pid_t pid;
	int status;

	if (DEBUG == true) printf(KILLER_NOTE1);

	while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
		if (DEBUG == true) {
			printf("%s %d\n", KILLER_NOTE2, pid);
		}
	}
	return;
}

/* Standardni ukonceni jeremyho */
void termination(int n)
{
	printf("%s\n", MSG_TERMINATION);
	exit(EXIT_SUCCESS);
}
